home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / share / pyshared / pycountry / db.py < prev    next >
Encoding:
Python Source  |  2010-04-21  |  2.4 KB  |  84 lines

  1. # vim:fileencoding=utf-8
  2. # Copyright (c) 2008 gocept gmbh & co. kg
  3. # See also LICENSE.txt
  4. # $Id$
  5. """Generic database code."""
  6.  
  7. import logging
  8. import lxml.etree
  9.  
  10. logger = logging.getLogger('pycountry.db')
  11.  
  12.  
  13. class Data(object):
  14.  
  15.     def __init__(self, element, **kw):
  16.         self._element = element
  17.         for key, value in kw.items():
  18.             setattr(self, key, value)
  19.  
  20.  
  21. class Database(object):
  22.  
  23.     # Override those names in sub-classes for specific ISO database.
  24.     field_map = dict()
  25.     data_class_base = Data
  26.     data_class_name = None
  27.     xml_tag = None
  28.     no_index = []
  29.  
  30.     def __init__(self, filename):
  31.         self.objects = []
  32.         self.indices = {}
  33.  
  34.         self.data_class = type(self.data_class_name, (self.data_class_base,),
  35.                                {})
  36.  
  37.         f = open(filename, 'rb')
  38.         etree = lxml.etree.parse(f)
  39.  
  40.         for entry in etree.xpath('//%s' % self.xml_tag):
  41.             mapped_data = {}
  42.             for key in entry.keys():
  43.                 mapped_data[self.field_map[key]] = entry.get(key)
  44.             entry_obj = self.data_class(entry, **mapped_data)
  45.             self.objects.append(entry_obj)
  46.  
  47.         # Construct list of indices: primary single-column indices
  48.         indices = []
  49.         for key in self.field_map.values():
  50.             if key in self.no_index:
  51.                 continue
  52.             # Slightly horrible hack: to evaluate `key` at definition time of
  53.             # the lambda I pass it as a keyword argument.
  54.             getter = lambda x, key=key: getattr(x, key, None)
  55.             indices.append((key, getter))
  56.  
  57.         # Create indices
  58.         for name, _ in indices:
  59.             self.indices[name] = {}
  60.  
  61.         # Update indices
  62.         for obj in self.objects:
  63.             for name, rule in indices:
  64.                 value = rule(obj)
  65.                 if value is None:
  66.                     continue
  67.                 if value in self.indices[name]:
  68.                     logger.error(
  69.                         '%s %r already taken in index %r and will be '
  70.                         'ignored. This is an error in the XML databases.' %
  71.                         (self.data_class_name, value, name))
  72.                 self.indices[name][value] = obj
  73.  
  74.     def __iter__(self):
  75.         return iter(self.objects)
  76.  
  77.     def __len__(self):
  78.         return len(self.objects)
  79.  
  80.     def get(self, **kw):
  81.         assert len(kw) == 1, 'Only one criteria may be given.'
  82.         field, value = kw.items()[0]
  83.         return self.indices[field][value]
  84.